package org.cx.comparator.map;

import org.cx.comparator.ComparatorConfiguration;
import org.cx.comparator.compare.mode.ComparatorType;
import lombok.Setter;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p> 参数映射构建者 </p>
 *
 */
public abstract class MapProcessor {

    @Setter
    private MapProcessor next;

    protected final ComparatorConfiguration comparatorConfiguration;

    public MapProcessor(ComparatorConfiguration comparatorConfiguration) {
        this.comparatorConfiguration = comparatorConfiguration;
    }


    /**
     * 获取对应方法的Map映射
     * @param method
     * @return
     */
    public final ComparatorMap build(Method method){
        if(matches(method)){
            final ComparatorMap currentMaps = doBuild(method);
            if(currentMaps!=null){
                return currentMaps;
            }
            if(currentMaps==null && next!=null){
                return next.doBuild(method);
            }
        }else{
            if(next!=null){
                return next.doBuild(method);
            }
        }
        return null;
    }

    /**
     * 是否直接执行下个处理器
     * @param method
     * @return
     */
    protected abstract boolean matches(Method method);

    /**
     * 构建参数
     * @param method
     * @return
     */
    protected abstract ComparatorMap doBuild(Method method);

    /**
     * 填充默认映射
     * @param sourceType
     * @param targetType
     * @param comparatorMap
     * @param excludes
     */
    protected void buildByDefaultField(Class sourceType, Class targetType, ComparatorMap comparatorMap, String[] excludes){
        //对相同字段生成对象映射
        final List<String> targetFieldNames = FieldUtils.getAllFieldsList(targetType).stream()
                .filter(field -> !Modifier.isStatic(field.getModifiers()))
                .map(field -> field.getName())
                .collect(Collectors.toList());

        final Set<ComparatorFieldMapping> fieldMappings = comparatorMap.getComparatorFieldMappings();
        final List<String> sourceList = fieldMappings.stream().map(mapping -> mapping.getSource()).collect(Collectors.toList());
        final List<Field> sourceFieldList = FieldUtils.getAllFieldsList(sourceType).stream()
                .filter(field -> !Modifier.isStatic(field.getModifiers()))
                .filter(field -> !sourceList.contains(field.getName()))
                .filter(field -> targetFieldNames.contains(field.getName()))
                .filter(field -> !Arrays.asList(excludes).contains(field.getName()))
                .collect(Collectors.toList());

        for (Field field : sourceFieldList) {
            ComparatorFieldMapping comparatorFieldMapping = new ComparatorFieldMapping(field.getName(),field.getName(),
                    ComparatorType.DEFAULT,null, null);
            fieldMappings.add(comparatorFieldMapping);
        }
    }

}
